﻿using System.Collections.ObjectModel;
using Digitalmes.ControlEx;
using Digitalmes.Infrastructure.Brokers.LedGuide;

namespace Digitalmes.Gallery.ViewModels.Pages;

public partial class LedCtlViewModel : ObservableObject, IDisposable
{
    record class LedProfileModel(string ProfileName, string FileName, LedProfile LedProfile);

    public record class LedResultModel(string No, double Torque, double Angle);

    private readonly string _profileDirPath;
    private readonly Dictionary<string, LedProfileModel> _profileMap = [];

    private readonly CancellationTokenSource _cts = new();

    private readonly LedGuideBroker _ledGuideBroker;
    private readonly IOptions<AppConfig> _options;

    public LedCtlViewModel(LedGuideBroker ledGuideBroker, IOptions<AppConfig> options)
    {
        _ledGuideBroker = ledGuideBroker;
        _options = options;

        _profileDirPath = Path.Combine(AppContext.BaseDirectory, "Assets", "LedProfiles", _options.Value.OpCode ?? "");
        this.LedCanvas = new()
        {
            ImageBaseDirectory = Path.Combine(AppContext.BaseDirectory, "Assets", "Images", _options.Value.OpCode ?? ""),
        };

        InitializeViewModel();
    }

    /// <summary>
    /// Led 画布
    /// </summary>
    [ObservableProperty]
    private LedCanvas _ledCanvas;

    /// <summary>
    /// 当前 Led 配方名称
    /// </summary>
    [ObservableProperty]
    private string? _currentProfileName;

    /// <summary>
    /// 是否启用点位编辑
    /// </summary>
    [ObservableProperty]
    private bool _enableEdit;

    /// <summary>
    /// 配方集合
    /// </summary>
    [ObservableProperty]
    private List<string>? _profileCollection;

    /// <summary>
    /// 绑定选中的下拉配置值
    /// </summary>
    [ObservableProperty]
    private string? _selectedProfileValue;

    /// <summary>
    /// 当前零件码
    /// </summary>
    [ObservableProperty]
    private string? _currentSerialNo = "000000 000000000000 000000000000 00000000";

    [ObservableProperty]
    private ObservableCollection<LedResultModel> _resultCollection = [];

    /// <summary>
    /// 启动/关闭点位编辑
    /// </summary>
    /// <param name="isChecked"></param>
    [RelayCommand]
    private void OnEnableEdit(bool isChecked)
    {
        EnableEdit = isChecked;
        LedCanvas.AllowMouseDrop = EnableEdit;
        ProfileCollection = ["", .. _profileMap.Keys];

        SelectedProfileValue = EnableEdit ? CurrentProfileName : "";
    }

    /// <summary>
    /// 下拉配方更改事件
    /// </summary>
    [RelayCommand]
    private void OnSelectProfileChanged()
    {
        var profileName = SelectedProfileValue;
        if (!string.IsNullOrEmpty(profileName))
        {
            SetProfile(profileName);
        }
    }

    /// <summary>
    /// 保存配方
    /// </summary>
    [RelayCommand]
    private void OnSaveProfile()
    {
        var profileName = SelectedProfileValue;
        if (string.IsNullOrEmpty(profileName))
        {
            return;
        }

        var profile = _profileMap[profileName];
        var leds = LedCanvas.GetCollection();
        foreach (var point in profile.LedProfile.Points)
        {
            var led = leds.FirstOrDefault(s => s.Index == point.Index && s.Group == point.Group);
            if (led != null)
            {
                point.X = Math.Round(led.CanvasPosition.X, 1);
                point.Y = Math.Round(led.CanvasPosition.Y, 1);
            }
        }

        var content = profile.LedProfile.ToJson(true);
        File.WriteAllText(Path.Combine(_profileDirPath, profile.FileName), content);
    }

    private void InitializeViewModel()
    {
        LoadProfile();
        SetProfile();
        Polling();
    }

    /// <summary>
    /// 加载配置文件
    /// </summary>
    private void LoadProfile()
    {
        // 从指定目录中找到配方文件
        if (!Directory.Exists(_profileDirPath))
        {
            return;
        }

        foreach (var path in Directory.GetFiles(_profileDirPath, "*.json", SearchOption.TopDirectoryOnly))
        {
            var content = File.ReadAllText(path);
            var ledProfile = content.FromJson<LedProfile>()!;
            _profileMap[ledProfile.Name] = new LedProfileModel(ledProfile.Name, Path.GetFileName(path), ledProfile);
        }
    }

    /// <summary>
    /// 设置配置
    /// </summary>
    /// <param name="profileName"></param>
    private void SetProfile(string? profileName = null)
    {
        var profile = profileName != null && _profileMap.TryGetValue(profileName, out var m)
            ? m
            : _profileMap.Values.FirstOrDefault(s => s.LedProfile.IsDefault) ?? _profileMap.Values.FirstOrDefault();
        if (profile != null)
        {
            CurrentProfileName = profile.ProfileName;
            LedCanvas.ChangeProfile(profile.LedProfile);
        }
    }

    /// <summary>
    /// 轮询读取监控数据
    /// </summary>
    private void Polling()
    {
        var dispatcher = Dispatcher.CurrentDispatcher; // 需在主线程中获取

        _ = Task.Run(async () =>
        {
            while (!_cts.IsCancellationRequested)
            {
                try
                {
                    var ledGuide = await _ledGuideBroker.DequeueAsync(_cts.Token); // 会阻塞等待
                    if (ledGuide is LedGuideTightenModel ledGuideModel)
                    {
                        await dispatcher.InvokeAsync(async () =>
                        {
                            await LedCanvas.ChangeStateAsync(ledGuideModel.Group, ledGuideModel.Index, ledGuideModel.Result);

                            if (ledGuideModel.Index > 0)
                            {
                                // 通过 Group+Index 获取编号名称
                                var led = LedCanvas.GetCollection().FirstOrDefault(s => s.Group == ledGuideModel.Group && s.Index == ledGuideModel.Index);
                                if (led != null)
                                {
                                    ResultCollection.Insert(0, new LedResultModel(led.Text ?? "", ledGuideModel.Torque, ledGuideModel.Angle));
                                }
                            }
                        });
                    }
                    else if (ledGuide is LedGuideSnModel ledGuideSnModel)
                    {
                        await dispatcher.InvokeAsync(() =>
                        {
                            ResultCollection.Clear(); // 切换 SN 后清空数据

                            // 配方变化，先切换配方，再重置状态
                            if (CurrentProfileName != ledGuideSnModel.ProfileName)
                            {
                                SetProfile(ledGuideSnModel.ProfileName);
                            }

                            CurrentSerialNo = ledGuideSnModel.SN;
                            LedCanvas.ResetState(); // 重置状态
                        });
                    };
                }
                catch (OperationCanceledException)
                {
                }
            }
        });
    }

    public void Dispose()
    {
        GC.SuppressFinalize(this);

        _cts.Cancel();
    }
}
